/* Copyright (C) 2011 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#include "physics_common.h"
#include "simulation_entity.h"

// this is the call back for allocation newton memory
void* TAllocMemory (int sizeInBytes)
{
	return malloc (sizeInBytes);
}

// this is the callback for freeing Newton Memory
void TFreeMemory (void *ptr, int sizeInBytes)
{
	free (ptr);
}

void TDestroyBodyCallback (const NewtonBody* body)
{
	//tri::TEntity* ent = NULL;
	
	// get the entity associated with this rigid body
	//ent = (tri::TEntity*) NewtonBodyGetUserData(body);
	
	//delete ent;
}

// Transform callback to set the matrix of a the visual entity
void TSetTransformCallback (const NewtonBody* body, const dFloat* matrix, int threadIndex)
{

	float angles[3];
	NewtonGetEulerAngle(matrix, angles);
	tri::TSimulationEntity* ent = (tri::TSimulationEntity*) NewtonBodyGetUserData(body);
	if (ent != NULL){
		
		if (!ent->ignoreRotation()){
			ent->getGraphicsComponent()->setRotation(tri::utils::radToDeg(angles[0]),
					tri::utils::radToDeg(angles[1]),
					tri::utils::radToDeg(angles[2]));
		}
		ent->getPhysicsModelComponent()->setRotation(tri::utils::radToDeg(angles[0]),
							tri::utils::radToDeg(angles[1]),
							tri::utils::radToDeg(angles[2]));
		ent->getPhysicsModelComponent()->setPosition(matrix[12],matrix[13],matrix[14]);
		ent->getGraphicsComponent()->setPosition(matrix[12],matrix[13],matrix[14]);
	}
}


// callback to apply external forces to body
void TApplyForceAndTorqueCallback (const NewtonBody* body, dFloat timestep, int threadIndex)
{
	dFloat Ixx;
	dFloat Iyy;
	dFloat Izz;
	dFloat mass;
	
	
	
	tri::TSimulationEntity* ent = (tri::TSimulationEntity*) NewtonBodyGetUserData(body);
	if (ent != NULL){
		tri::TVector gravity(0.0f, ent->getMass() * -10, 0.0f);
		gravity+=ent->getForce();
		ent->setForce(tri::TVector(0,0,0));
		
		// for this tutorial the only external force in the Gravity
		NewtonBodyGetMassMatrix (body, &mass, &Ixx, &Iyy, &Izz);
		NewtonBodySetForce(body, &gravity[0]);
	}
}

int TGenMaterialGroup(const NewtonWorld* newtonWorld){
	if(newtonWorld==0){
		return -1;
	}
	return  NewtonMaterialCreateGroupID(newtonWorld);
}

//configure the Material interactions
void TRegisterCollisionsType(NewtonWorld* newtonWorld, int mat1, int mat2, void* meta, void (*GenericContactProcess) (const NewtonJoint*, dFloat, int)){
	NewtonMaterialSetCollisionCallback (newtonWorld, mat1, mat2, meta, NULL,  GenericContactProcess);
}

namespace tri{

TPhysicsUpdateThread::TPhysicsUpdateThread(NewtonWorld* world) :
	tri::TThread(), m_NewtonWorld(world), m_UpdateRecursion(10) {

}

TPhysicsUpdateThread::~TPhysicsUpdateThread() {
}

void TPhysicsUpdateThread::run() {
	while (!terminateRequested()) {
		tri::utils::sleep(2);
		for (unsigned int i=0;i<m_UpdateRecursion;i++){
			NewtonUpdate (m_NewtonWorld, 0.002);
		}
	}
}

void TPhysicsUpdateThread::setUpdateRecursion(unsigned int ur){
	m_UpdateRecursion = ur;
}

}
